using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Pex.Framework;

namespace ReactiveLang
{
    using Expressions;

    [TestClass]
    public partial class WeakRefTests
    {
        TestSyncContext _ctx;
        [TestInitialize]
        public void InitializeTest()
        {
            _ctx = new TestSyncContext();
            System.Threading.SynchronizationContext.SetSynchronizationContext(_ctx);
        }
        [TestCleanup]
        public void TestCleanup()
        {
            System.Threading.SynchronizationContext.SetSynchronizationContext(null);
        }

        void Collect()
        {
            GC.Collect(); GC.WaitForPendingFinalizers();
            GC.Collect(); GC.WaitForPendingFinalizers();
            GC.Collect(); GC.WaitForPendingFinalizers();
        }

        [TestMethod]
        public void ReactiveCodeMustDieWithoutHost()
        {
            var a = new Variable<int>();
            var b = new Variable<int>();

            Func<WeakReference> reactive = delegate
            {
                var host = new ReactiveHost();
                var handle = host.Add(Expression.Assign(a.MakeWeak(), b.MakeWeak()));
                return new WeakReference(host);
            };
            var wr = reactive();
            Collect();

            b.Value = 54;
            _ctx.RunQueue();
            Assert.IsFalse(wr.IsAlive);
            Assert.AreNotEqual(a.Value, b.Value);
        }

        [PexMethod]
        public void MakeWeakTest(bool keepHandle)
        {
            var src = new Variable<int>();
            int dest = 0;
            IDisposable handle = null;

            Func<WeakReference> subscribeWeak = () =>
            {
                var weakSrc = src.MakeWeak();
                var h = weakSrc.Activate(x => dest = x);
                if (keepHandle)
                    handle = h;
                return new WeakReference(weakSrc);
            };

            var wr = subscribeWeak();

            Collect();
            src.Value = 54;
            Collect();

            Assert.AreEqual(keepHandle, wr.IsAlive);
            Assert.AreEqual(keepHandle, src.Value == dest);
            GC.KeepAlive(handle);
        }
    }
}